home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
CW GUSI 1.6.4
/
src
/
GUSIFileDispatch.cp
< prev
next >
Wrap
Text File
|
1995-11-05
|
9KB
|
415 lines
/*********************************************************************
Project : GUSI - Grand Unified Socket Interface
File : GUSIFileDispatch.cp - Dispatch calls to their correct recipient
Author : Matthias Neeracher
Language : MPW C/C++
$Log: GUSIFileDispatch.cp,v $
Revision 1.1 1994/12/30 19:59:55 neeri
Initial revision
*********************************************************************/
#include "GUSIFile_P.h"
#include "GUSIMPW_P.h"
#include <Errors.h>
#include <utime.h>
#if GENERATINGCFM
#include <FragLoad.h>
#endif
#pragma segment GUSI
/************************ External routines *************************/
int open(const char * filename, int oflag)
{
Sockets.InitConsole();
Socket * sock;
int fd;
GUSIFileRef ref(filename, FileSocketDomain::willOpen);
if (ref.Domain()) {
errno = 0;
if (sock = ref.Domain()->open(ref, oflag))
if ((fd = Sockets.Install(sock)) != -1)
return fd;
else
delete sock;
if (!errno)
return GUSI_error(ENOMEM);
else
return -1;
} else
return GUSI_error(EINVAL);
}
int creat(const char* filename)
{
return open(filename, O_WRONLY | O_TRUNC | O_CREAT);
}
int remove(const char *filename)
{
GUSIFileRef ref(filename, FileSocketDomain::willRemove, true);
if (ref.Domain())
return ref.Domain()->remove(ref);
else
return GUSI_error(EINVAL);
}
int unlink(char* filename)
{
GUSIFileRef ref(filename, FileSocketDomain::willRemove, true);
if (ref.Domain())
return ref.Domain()->remove(ref);
else
return GUSI_error(EINVAL);
}
int rename(const char *oldname, const char *newname)
{
GUSIFileRef ref(oldname, FileSocketDomain::willRename, true);
if (ref.Domain())
return ref.Domain()->rename(ref, newname);
else
return GUSI_error(EINVAL);
}
void fsetfileinfo(char *filename, unsigned long newcreator, unsigned long newtype)
{
GUSIFileRef ref(filename, FileSocketDomain::willSetFileInfo);
if (ref.Domain())
ref.Domain()->fsetfileinfo(ref, newcreator, newtype);
else
GUSI_error(EINVAL);
}
void fgetfileinfo(char *filename, unsigned long * creator, unsigned long * type)
{
GUSIFileRef ref(filename, FileSocketDomain::willGetFileInfo);
if (ref.Domain())
ref.Domain()->fgetfileinfo(ref, creator, type);
else
GUSI_error(EINVAL);
}
int faccess(char* filename, unsigned int cmd, long* arg)
{
GUSIFileRef ref(filename, FileSocketDomain::willFAccess);
if (ref.Domain())
return ref.Domain()->faccess(ref, cmd, arg);
else
return GUSI_error(EINVAL);
}
int truncate(const char* filename, off_t offset)
{
int res;
int fd = open(filename, O_RDWR);
if (fd == -1)
return -1;
res = ftruncate(fd, offset);
close(fd);
return res;
}
int stat(const char * path, struct stat * buf)
{
GUSIFileRef ref(path, FileSocketDomain::willStat);
if (ref.Domain())
return ref.Domain()->stat(ref, buf);
else
return GUSI_error(EINVAL);
}
int lstat(const char * path, struct stat * buf)
{
GUSIFileRef ref(path, FileSocketDomain::willStat, true);
if (ref.Domain())
return ref.Domain()->stat(ref, buf);
else
return GUSI_error(EINVAL);
}
int chmod(const char * filename, mode_t mode)
{
GUSIFileRef ref(filename, FileSocketDomain::willChmod);
if (ref.Domain())
return ref.Domain()->chmod(ref, mode);
else
return GUSI_error(EINVAL);
}
int utime(const char * path, const struct utimbuf * times)
{
GUSIFileRef ref(path, FileSocketDomain::willUTime);
if (ref.Domain())
return ref.Domain()->utime(ref, times);
else
return GUSI_error(EINVAL);
}
int access(const char * path, int mode)
{
GUSIFileRef ref(path, FileSocketDomain::willAccess);
if (ref.Domain())
return ref.Domain()->access(ref, mode);
else
return GUSI_error(EINVAL);
}
/************************ class GUSIFileRef *************************/
#ifndef GUSI_DISPATCH
// Identifying a name starting with dev: as a file or a device is
// a dangerous job. Currently, there is no possibility to entirely
// disable device interpretation, so we're using the following
// heuristics in order to minimize conflicts with real file names:
// - Any name corresponding to an existing file is a file
// - Any name not recognized by any device domain is a file
GUSIFileRef::GUSIFileRef(const char * name, FileSocketDomain::Request request, Boolean useAlias)
: hasInfo(false), name(name), file(name, useAlias)
{
if (!::IsDevice(name) || (!file.Error() && file.Exists()))
goto isFile;
spec = nil;
domain = FileSocketDomain::FindDomain(*this, request);
if (!domain)
goto isFile;
error = noErr;
return;
isFile:
spec = &file;
error = file.Error();
domain= FileSocketDomain::FindDomain(*this, request);
}
GUSIFileRef::GUSIFileRef(short fRefNum, FileSocketDomain::Request request)
: hasInfo(false), name(nil), file(fRefNum)
{
spec = &file;
error = file.Error();
domain= FileSocketDomain::FindDomain(*this, request);
}
const CInfoPBRec * GUSIFileRef::Info() const
{
if (!hasInfo) {
if (!spec) {
((GUSIFileRef *) this)->error = paramErr;
return nil;
}
if (((GUSIFileRef *) this)->error = file.CatInfo(((GUSIFileRef *) this)->info))
return nil;
((GUSIFileRef *) this)->hasInfo = true;
}
return &info;
}
/************************ class FileSocketDomain *************************/
// Only the domain management part is found here. For the file specific part,
// see GUSIFile.cp
FileSocketDomain * FileSocketDomain::firstDeviceDomain = nil;
FileSocketDomain * FileSocketDomain::lastDeviceDomain = nil;
FileSocketDomain * FileSocketDomain::firstFileDomain = nil;
FileSocketDomain * FileSocketDomain::lastFileDomain = nil;
void Enqueue(
FileSocketDomain * current,
FileSocketDomain * FileSocketDomain::* next,
FileSocketDomain ** first,
FileSocketDomain ** last)
{
current->*next = FileSockets;
if (*last)
(*last)->*next = current;
else
*first = current;
*last = current;
}
void Dequeue(
FileSocketDomain * current,
FileSocketDomain * FileSocketDomain::* next,
FileSocketDomain ** first,
FileSocketDomain ** last)
{
FileSocketDomain * pred = nil;
if (!*first)
return;
if (*first == current)
*first = current->*next;
else {
for (pred = *first; pred->*next && pred->*next != current;)
pred = pred->*next;
if (pred->*next == current)
pred->*next = current->*next;
else
return;
}
if (*last == current)
*last = pred;
}
static Boolean HandleFileDispatch = true;
static FileSocketDomain * NullSockets;
FileSocketDomain::FileSocketDomain(
int domain,
Boolean doesDevices,
Boolean doesFiles)
: SocketDomain(domain)
{
if (!FileSockets && HandleFileDispatch) {
FileSockets = new FileSocketDomain;
NullSockets = new NullSocketDomain;
}
if (doesDevices)
Enqueue(
this,
&FileSocketDomain::nextDeviceDomain, &firstDeviceDomain, &lastDeviceDomain);
if (doesFiles)
Enqueue(
this,
&FileSocketDomain::nextFileDomain, &firstFileDomain, &lastFileDomain);
}
FileSocketDomain::~FileSocketDomain()
{
if (this == FileSockets) {
FileSockets = nil;
HandleFileDispatch = false;
}
Dequeue(
this,
&FileSocketDomain::nextDeviceDomain, &firstDeviceDomain, &lastDeviceDomain);
Dequeue(
this,
&FileSocketDomain::nextFileDomain, &firstFileDomain, &lastFileDomain);
}
FileSocketDomain * FileSocketDomain::FindDomain(
const GUSIFileRef & ref, Request request)
{
FileSocketDomain * dom;
FileSocketDomain * FileSocketDomain::* next;
// We are already decomposing
if (!FileSockets)
if (!HandleFileDispatch)
return nil;
else
FileSockets = new FileSocketDomain;
if (ref.IsDevice()) {
dom = firstDeviceDomain;
next = &FileSocketDomain::nextDeviceDomain;
} else {
dom = firstFileDomain;
next = &FileSocketDomain::nextFileDomain;
}
// FileSockets will handle *everything*, therefore loop guaranteed to terminate
while (dom && !dom->Yours(ref, request))
dom = dom->*next;
return dom;
}
// Quod licet Jovi non licet bovi
FileSocketDomain::FileSocketDomain()
: SocketDomain(AF_FILE)
{
firstFileDomain = firstDeviceDomain = this;
nextFileDomain = nextDeviceDomain = nil;
}
Boolean FileSocketDomain::Yours(const GUSIFileRef & ref, Request req)
{
// We handle all plain files and willOpen/willStat for the console
if (!ref.IsDevice())
return true;
else if (req != willOpen && req != willStat)
return false;
switch (ref.name[4] | 0x20) {
case 's':
if ((ref.name[5] | 0x20) != 't' || (ref.name[6] | 0x20) != 'd')
return false;
switch (ref.name[7] | 0x20) {
case 'i':
if ((ref.name[8] | 0x20) != 'n' || ref.name[9])
return false;
return true;
case 'o':
if ((ref.name[8] | 0x20) != 'u' || (ref.name[9] | 0x20) != 't' || ref.name[10])
return false;
return true;
case 'e':
if ((ref.name[8] | 0x20) != 'r' || (ref.name[9] | 0x20) != 'r' || ref.name[10])
return false;
return true;
default:
return false;
}
case 'c':
if ( (ref.name[5] | 0x20) != 'o' || (ref.name[6] | 0x20) != 'n'
|| (ref.name[7] | 0x20) != 's' || (ref.name[8] | 0x20) != 'o'
|| (ref.name[9] | 0x20) != 'l' || (ref.name[10] | 0x20) != 'e'
|| ref.name[11])
return false;
return true;
case 'n':
if ( (ref.name[5] | 0x20) != 'u' || (ref.name[6] | 0x20) != 'l'
|| (ref.name[7] | 0x20) != 'l' || ref.name[8])
return false;
return true;
default:
return false;
}
}
#endif // GUSI_DISPATCH